package service

import (
	"errors"
	"gorm.io/gorm"
	"shop-common/library/loggerV2"
	"shop-common/library/variables"
	"shop-common/utils/queryWrapper"
	"shop-sys/model"
	"shop-sys/pkg/constant"
	"shop-sys/pkg/request"
	"shop-sys/pkg/vo"
	"shop-sys/repository"
	"strings"
)

type ISysMenuService interface {
	ListMenuAndBtn() ([]*model.SysMenu, error)
	ListMenuByUserId(userId uint) (rootMenu []*vo.SysMenuVO, err error)
	FindMenuIdByRoleId(roleId uint) (list []uint)
	FindByRoleIdPerms(roleIds []uint) (map[uint][]string, error)
	Create(request *request.SysMenuRequest) error
	FindByParentId(wp *queryWrapper.WherePair) (sysMenu *model.SysMenu, err error)
	ListSimpleMenuNoButton() ([]*vo.SimpleMenuVO, error)
	ListRootMenu() ([]*vo.SimpleMenuVO, error)
	ListChildrenMenuByParentId(parentId uint) ([]*vo.SimpleMenuVO, error)
	FinById(menuId uint) (*model.SysMenu, error)
	DeleteMenuAndRoleMenu(menuId uint) error
	UpdateById(menuId uint, columns map[string]interface{}) error
}

func NewSysMenuService(

) ISysMenuService {
	return &SysMenuService{variables.GormDB(), repository.NewSysMenuRepository(), repository.NewSysRoleMenuRepository()}
}

type SysMenuService struct {
	db                    *gorm.DB
	sysMenuRepository     repository.ISysMenuRepository
	sysRoleMenuRepository repository.ISysRoleMenuRepository
}

/**
 * 获取菜单页面的表
 * @return
 */
func (s *SysMenuService) ListMenuAndBtn() ([]*model.SysMenu, error) {

	sysMenuList, err := s.sysMenuRepository.FindListMenuAndBtn(s.db)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Error(err)
		return nil, err
	}
	return sysMenuList, nil
}

/**
 * 获取用户菜单列表
 * @param userId 用户id
 * @return 菜单列表
 */
func (s *SysMenuService) ListMenuByUserId(userId uint) (rootMenu []*vo.SysMenuVO, err error) {
	// 用户的所有菜单信息
	var sysMenus []*model.SysMenu

	//系统管理员，拥有最高权限
	if userId == constant.SUPER_ADMIN_ID {
		sysMenus, err = s.sysMenuRepository.FindListMenu(s.db)
		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
			loggerV2.Errorf("findListMenu vo.SysMenuVO failed: err %v, userId %d", err, userId)
			return
		}
	} else {
		sysMenus, err = s.sysMenuRepository.FindListMenuByUserId(s.db, userId)
		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
			loggerV2.Error(err)
			return
		}
	}
	if sysMenus == nil || len(sysMenus) == 0 {
		return
	}
	// 组装数据，递归tree
	return getJsonTree(sysMenus, 0), nil
}

func getJsonTree(menuTrees []*model.SysMenu, parentId uint) (trees []*vo.SysMenuVO) {
	for _, menuTree := range menuTrees {
		if menuTree.ParentId == parentId {
			newNode := &vo.SysMenuVO{
				MenuId:     menuTree.MenuId,
				ParentId:   menuTree.ParentId,
				ParentName: getParentName(menuTrees, menuTree.ParentId),
				Name:       menuTree.Name,
				Url:        menuTree.Url,
				Perms:      menuTree.Perms,
				Type:       menuTree.Type,
				Icon:       menuTree.Icon,
				OrderNum:   menuTree.OrderNum,
				List:       getJsonTree(menuTrees, menuTree.MenuId),
			}
			trees = append(trees, newNode)
		}
	}
	return trees
}

/**
 * 根据角色ID，获取菜单列表
 * @param roleId 角色id
 * @return 角色所拥有的菜单id列表
 */
func (s *SysMenuService) FindMenuIdByRoleId(roleId uint) (list []uint) {
	sysRoleMenu, err := s.sysRoleMenuRepository.FindById(s.db, roleId)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Errorf("findMenuId byRoleId filed: err %v, roleId %d", err, roleId)
		return list
	}

	for _, menuId := range sysRoleMenu {
		list = append(list, menuId.MenuId)
	}

	return list
}

func getParentName(menuTrees []*model.SysMenu, menuId uint) string {
	var name string
	for _, menuTree := range menuTrees {
		if menuTree.MenuId == menuId {
			return menuTree.Name
		}
	}
	return name
}

//如果不传则查询全部角色
func (s *SysMenuService) FindByRoleIdPerms(roleIds []uint) (map[uint][]string, error) {
	perms, err := s.sysRoleMenuRepository.FindInRoleIdPerms(s.db, roleIds)
	if err != nil {
		loggerV2.Errorf("findByRoleIdPerms by RoleIds filed: err %v, roleIds %d", err, roleIds)
		return nil, err
	}

	if variables.GlobalRolePermission == nil {
		variables.GlobalRolePermission = make(map[uint][]string)
	}

	for _, srm := range perms {
		variables.GlobalRolePermission[srm.RoleId] = append(variables.GlobalRolePermission[srm.RoleId], strings.Split(srm.Perms, ",")...)
	}

	return variables.GlobalRolePermission, nil
}

//保存菜单
func (s *SysMenuService) Create(request *request.SysMenuRequest) error {
	sysMenu := &model.SysMenu{
		ParentId: request.ParentId,
		Name:     request.Name,
		Url:      request.Url,
		Perms:    request.Perms,
		Type:     request.Type,
		Icon:     request.Icon,
		OrderNum: request.OrderNum,
	}

	_, err := s.sysMenuRepository.Create(s.db, sysMenu)
	if err != nil {
		loggerV2.Error(err)
		return err
	}
	return nil
}

func (s *SysMenuService) FindByParentId(pair *queryWrapper.WherePair) (sysMenu *model.SysMenu, err error) {
	sysMenu, err = s.sysMenuRepository.FindOne(s.db, pair)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Errorf("findOne by pair sysMenu: err %v, pair %+v", err, pair)
		return
	}

	return sysMenu, nil
}

/**
 * 获取简单的menu tree 用于在ele-ui tree中显示，根据orderNum排序
 * @return 所有的菜单
 */
func (s *SysMenuService) ListSimpleMenuNoButton() ([]*vo.SimpleMenuVO, error) {
	simpleSysMenu, err := s.sysMenuRepository.FindListSimpleMenuNoButton(s.db)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Error(err)
		return nil, err
	}
	return simpleSysMenu, nil
}

/**
 * 获取一级菜单
 * @return 一级菜单列表
 */
func (s *SysMenuService) ListRootMenu() ([]*vo.SimpleMenuVO, error) {
	simpleMenu, err := s.sysMenuRepository.FindListRootMenu(s.db)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Error(err)
		return nil, err
	}
	return simpleMenu, nil
}

/**
 * 根据一级菜单id 获取二级菜单
 * @param parentId 一级菜单id
 * @return 二级菜单列表
 */
func (s *SysMenuService) ListChildrenMenuByParentId(parentId uint) ([]*vo.SimpleMenuVO, error) {
	simpleMenu, err := s.sysMenuRepository.FindListChildrenMenuByParentId(s.db, parentId)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Error(err)
		return nil, err
	}
	return simpleMenu, nil
}

/**
 * 菜单信息
 */
func (s *SysMenuService) FinById(menuId uint) (*model.SysMenu, error) {
	sysMenu, err := s.sysMenuRepository.FindById(s.db, menuId)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Errorf("FindById to sysMenu failed: err %v, menuId %d", err, menuId)
		return nil, err
	}

	return sysMenu, nil
}

/**
 * 删除 菜单，与角色菜单之间的关系
 * @param menuId 菜单id
 */
func (s *SysMenuService) DeleteMenuAndRoleMenu(menuId uint) error {
	return s.db.Transaction(func(tx *gorm.DB) error {
		//删除菜单
		err := s.sysMenuRepository.Delete(tx, menuId)
		if err != nil {
			loggerV2.Errorf("by menuId delete sysMenu failed: err %v, menuId %d", err, menuId)
			return err
		}

		//删除菜单与角色关联
		err = s.sysRoleMenuRepository.DeleteBatch(tx, "menu_id = ?", []uint{menuId})
		if err != nil {
			loggerV2.Errorf("by menuId batch delete sysRole and sysMenu association failed: err %v, menuId %d", err, menuId)
			return err
		}

		return nil
	})
}

func (s *SysMenuService) UpdateById(menuId uint, columns map[string]interface{}) error {
	err := s.sysMenuRepository.Updates(s.db, menuId, columns)
	if err != nil {
		loggerV2.Error(err)
		return err
	}

	return nil
}
